// ==================================================================================
// Shared Genomics Project MPI Codebase
// Version 1.0 30/04/2010
//
// (c) 2010 University of Manchester all rights reserved
//
// This file is distributed under the GNU General Public License, Version 2.  
// Please see the file COPYING.txt for more details
// ==================================================================================

/*!
\file 
\brief Implementation of Sample/Phenotype Methods
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "copyfile.h"
#include "sample.h"
#include "individual.h"
#include "suffixes.h"

int samplefile_create(struct selected_options *ops, struct pedfile *ped) {
	FILE *fout = NULL;
	struct sample s;
	int i;

	if (ops == NULL || ped == NULL) return 0;
	else if (strlen(ops->szSampleFileName) == 0) return 0;
	else if (ped->nSample == 0) return 0;

	fout = fopen(ops->szSampleFileName, "wb");
	if (fout == NULL) return 0;

	if (fwrite(&(ped->nSample), sizeof(int), 1, fout) != 1) {
		if (fout != NULL) fclose(fout);
		return 0;
	}

	// Write the case data to the output file.
	s.pperson = NULL;
	for (i = 0; i < ped->nSample; i++) {
		struct individual *person = ped->sample[i];
		if (person == NULL) {
			if (fout != NULL) fclose(fout);
			return 0;
		} else {
			s.missing = person->missing;
			s.sex = person->sex;
			s.aff = person->aff;
			s.phenotype = person->phenotype;
			s.sol = DEFAULT_SOL;

			// Write the structure to the output file.
			if (fwrite(&s, sizeof(struct sample), 1, fout) != 1) {
				if (fout != NULL) fclose(fout);
				return 0;
			}
		} 
	}
	if (fout != NULL) fclose(fout);

	return 1;
}

// Return an array of cases.
struct sample* samplefile_load(struct selected_options *ops, int *nSamples) {
	struct sample* pValues = NULL;
	FILE *fin = NULL;
	int sample_read_count = 0;

	if (ops == NULL || nSamples == NULL) return NULL;
	else if (strlen(ops->szSampleFileName) == 0) return NULL;

	fin = fopen(ops->szSampleFileName, "rb");
	if (fin == NULL) return NULL;

	// Read the number of samples in the file.
	if (fread(nSamples, sizeof(int), 1, fin) != 1) {
		if (fin != NULL) fclose(fin);
		return pValues;
	}

	// Shouldn't be zero samples in the input file.
	if (*nSamples <= 0) {
		if (fin != NULL) fclose(fin);
		return pValues;
	}

	pValues = (struct sample*) malloc(sizeof(struct sample) * (*nSamples));
	if (pValues == NULL) {
		if (fin != NULL) fclose(fin);
		return NULL;
	}

	// Read in the phenotype array.
	sample_read_count = (int) fread(pValues, sizeof(struct sample),*nSamples, fin);
	if (sample_read_count != (*nSamples)) {
		if (pValues != NULL) free(pValues);
		*nSamples = 0;
		return NULL;
	}

	if (fin != NULL) fclose(fin);

	return pValues;
}

int samplefile_set_original_order(struct sample *samples, int nSamples) {
	int i;
	struct sample *s = samples;

	if (samples == NULL || nSamples == 0) return 0;
	else for (i = 0, samples = s; i < nSamples; i++, s++) s->pperson = s;

	return 1;
}

int samplefile_aff_coding(struct sample *samples, int nSamples) {
	int i;

	if (samples == NULL || nSamples == 0) return 0;

	for (i = 0; i < nSamples; i++) {
		if (samples[i].phenotype == 2 && !samples[i].missing) 
			samples[i].aff = TRUE;
		else
			samples[i].aff = FALSE;
	}

	return 1;
}

int samplefile_permute_phenotype(struct sample *samples, int *perms, int nSamples) {
	int i;

	if (samples == NULL || perms == NULL || nSamples == 0) return 0; 

	for (i = 0; i < nSamples; i++, perms++) samples[i].pperson = &samples[*perms];

	return 1;
}

int samplefile_set_missing(BOOL *missing, int nMissing, struct sample *s) {
	int i;

	if (missing == NULL || s == NULL) return 0;
	else if (nMissing <= 0) return 0;

	for (i = 0; i < nMissing; i++) {
		missing[i] = FALSE;
		if (s[i].missing) missing[i] = TRUE;	
	}

	return 1;
}

int samplefile_set_missing_by_sol(struct sample *s, int nSamples) {
	int i;
	if (s == NULL || nSamples <= 0) return 0;

	for (i = 0; i < nSamples; i++) if (s[i].sol == DEFAULT_SOL) s[i].missing = TRUE;

	return 1;
}

int samplefile_create_and_copy(struct selected_options *ops, struct pedfile *p, int rank) {
	BOOL jobDone = FALSE;
	char tmp_szRunId[TOKEN_LENGTH], remoteFilepath[FILE_PATH_LENGTH];

	if (p == NULL || ops == NULL) return 0;

	strcpy(tmp_szRunId, ops->szRunId);
	sprintf(ops->szRunId, "%s_%i", tmp_szRunId, rank);

	sprintf(ops->szSampleFileName, "%s%s%s_%i", ops->ldir, ops->szRunId, SUFFIX_SAMPLE_FILE, rank);
	sprintf(remoteFilepath, "%s%s%s", ops->rdir, tmp_szRunId, SUFFIX_SAMPLE_FILE);

	if (samplefile_create(ops, p))  if (copyAndDeleteFile(ops->szSampleFileName, remoteFilepath)) jobDone = TRUE;

	strcpy(ops->szRunId, tmp_szRunId); // Restore the original Run ID

	if (jobDone) return 1;
	else return 0;
}

struct sample* _samplefile_load(struct selected_options *ops, int *nSamples) {
	if (ops == NULL || nSamples == NULL) return NULL;

	sprintf(ops->szSampleFileName, "%s%s%s", ops->rdir, ops->szRunId, SUFFIX_SAMPLE_FILE);

	return samplefile_load(ops, nSamples);
}

int _samplefile_create_and_copy(struct selected_options *ops, double *phenotypes, BOOL *phe_is_missing, int nPhenotypes, BOOL *sex) {
	struct sample* samples = NULL;
	BOOL jobDone = FALSE;
	char localFilepath[FILE_PATH_LENGTH], remoteFilepath[FILE_PATH_LENGTH];
	FILE *out = NULL;

	if (ops == NULL || phenotypes == NULL || nPhenotypes <= 0 || phe_is_missing == NULL || sex == NULL) return 0;
	else if (strlen(ops->ldir) == 0 || strlen(ops->rdir) == 0 || strlen(ops->szRunId) == 0) return 0;

	sprintf(localFilepath, "%s%s%s", ops->ldir, ops->szRunId, SUFFIX_SAMPLE_FILE);
	sprintf(remoteFilepath, "%s%s%s", ops->rdir, ops->szRunId, SUFFIX_SAMPLE_FILE);

	samples = (struct sample*) malloc(sizeof(struct sample) * nPhenotypes);
	if (samples != NULL) {
		out = fopen(localFilepath, "wb");
		if (out != NULL) {
			int i;
			for (i = 0; i < nPhenotypes; i++) {
				samples[i].phenotype = phenotypes[i];
				samples[i].sex = sex[i];
				samples[i].aff = FALSE;
				samples[i].sol = DEFAULT_SOL;
				samples[i].pperson = NULL;

				if (phe_is_missing[i]) samples[i].missing = TRUE;
				else samples[i].missing = FALSE;
			}
			if (fwrite(&nPhenotypes, sizeof(int), 1, out) == 1) {
				if(fwrite(samples, sizeof(struct sample), nPhenotypes, out) == nPhenotypes) jobDone = TRUE;
			}
			fclose(out);
			out = NULL;
			if (!jobDone) deleteFile(localFilepath); // If failed, delete the intermediate file on local disk.
		}
		if (samples != NULL) free(samples);
	}

	// Copy the output file to the central file server.
	if (jobDone) jobDone = copyAndDeleteFile(localFilepath, remoteFilepath) ? TRUE : FALSE;

	if (jobDone) return 1;
	else return 0;
}

void sample_echo(struct sample *s) {
	if (s != NULL) {
		fprintf(stdout, "phe=%10.8f\taff=%i\tsex=%i\tmissing=%i\n", s->phenotype, s->aff, s->sex, s->missing);
	}
}